/*
 * 2011 Foxykeep (http://datadroid.foxykeep.com)
 *
 * Licensed under the Beerware License :
 * 
 *   As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think
 *   this stuff is worth it, you can buy me a beer in return
 */
package com.example.http;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.inputmethodservice.Keyboard;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.util.Log;
import android.util.SparseArray;


import com.llkj.cm.restfull.network.NetworkConnection;
import com.llkj.cm.restfull.requestmanager.RequestManager;

/**
 * This class is used as a proxy to call the Service. It provides easy-to-use
 * methods to call the service and manages the Intent creation. It also assures
 * that a request will not be sent again if an exactly identical one is already
 * in progress
 * 
 * @author Foxykeep
 */
public class PoCRequestManager extends RequestManager {
	private static final int MAX_RANDOM_REQUEST_ID = 1000000;

	// Singleton management
	private static PoCRequestManager sInstance;
	//单利模式构建类对象
	public static PoCRequestManager from(final Context context) {
		//如果为空创建
		if (sInstance == null) {
			sInstance = new PoCRequestManager(context);
			// 要调用此方法,生成UA
			NetworkConnection.generateDefaultUserAgent(context);
		}
		//不为空，返回
		return sInstance;
	}

	private static Random sRandom = new Random();

	private SparseArray<Intent> mRequestSparseArray;
	private Context mContext;
	//弱引用，放监听回调接口
	private ArrayList<WeakReference<OnRequestFinishedListener>> mListenerList;
	private Handler mHandler = new Handler();
	private EvalReceiver mEvalReceiver = new EvalReceiver(mHandler);

	private PoCRequestManager(final Context context) {
		mContext = context.getApplicationContext();
		mRequestSparseArray = new SparseArray<Intent>();
		mListenerList = new ArrayList<WeakReference<OnRequestFinishedListener>>();
	}

	/**
	 * The ResultReceiver that will receive the result from the Service
	 */
	private class EvalReceiver extends ResultReceiver {
		EvalReceiver(final Handler h) {
			super(h);
		}

		@Override
		public void onReceiveResult(final int resultCode,
				final Bundle resultData) {
			handleResult(resultCode, resultData);
		}
	}

	/**
	 * Clients may implements this interface to be notified when a request is
	 * finished
	 * 
	 * @author Foxykeep
	 */
	public static interface OnRequestFinishedListener extends EventListener {

		/**
		 * Event fired when a request is finished.
		 * 
		 * @param requestId
		 *            The request Id (to see if this is the right request)
		 * @param resultCode
		 *            The result code (0 if there was no error)
		 * @param payload
		 *            The result of the service execution.
		 */
		public void onRequestFinished(int requestId, int resultCode,
				Bundle payload);

		/**
		 * Prepare before a request will be called;
		 * 
		 * @author zhang.zk
		 * 
		 */
		public void onRequestPrepareListener();
	}

	/**
	 * Add a {@link OnRequestFinishedListener} to this {@link PoCRequestManager}
	 * . Clients may use it in order to listen to events fired when a request is
	 * finished.
	 * <p>
	 * <b>Warning !! </b> If it's an {@link Activity} that is used as a
	 * Listener, it must be detached when {@link Activity#onPause} is called in
	 * an {@link Activity}.
	 * </p>
	 * 
	 * @param listener
	 *            The listener to add to this {@link PoCRequestManager} .
	 */
	public void addOnRequestFinishedListener(
			final OnRequestFinishedListener listener) {
		synchronized (mListenerList) {
			// Check if the listener is not already in the list
			if (!mListenerList.isEmpty()) {
				for (WeakReference<OnRequestFinishedListener> weakRef : mListenerList) {
					if (weakRef.get() != null) {
						if (weakRef.get().equals(listener)) {
							return;
						}
					}
				}
			}

			mListenerList.add(new WeakReference<OnRequestFinishedListener>(
					listener));
		}
	}

	/**
	 * Remove a {@link OnRequestFinishedListener} to this
	 * {@link PoCRequestManager}.
	 * 
	 * @param listenerThe
	 *            listener to remove to this {@link PoCRequestManager}.
	 */
	public void removeOnRequestFinishedListener(
			final OnRequestFinishedListener listener) {
		synchronized (mListenerList) {
			final int listenerListSize = mListenerList.size();
			for (int i = 0; i < listenerListSize; i++) {
				if (mListenerList.get(i).get() != null) {
					if (mListenerList.get(i).get().equals(listener)) {
						mListenerList.remove(i);
						return;
					}
				}
			}
		}
	}

	/**
	 * Return whether a request (specified by its id) is still in progress or
	 * not
	 * 
	 * @param requestId
	 *            The request id
	 * @return whether the request is still in progress or not.
	 */
	public boolean isRequestInProgress(final int requestId) {
		return (mRequestSparseArray.indexOfKey(requestId) >= 0);
	}

	/**
	 * This method is call whenever a request is finished. Call all the
	 * available listeners to let them know about the finished request
	 * 
	 * @param resultCode
	 *            The result code of the request
	 * @param resultData
	 *            The bundle sent back by the service
	 */
	protected void handleResult(final int resultCode, final Bundle resultData) {

		// Get the request Id
		final int requestId = resultData.getInt(RECEIVER_EXTRA_REQUEST_ID);

		// Remove the request Id from the "in progress" request list
		mRequestSparseArray.remove(requestId);

		// Call the available listeners
		synchronized (mListenerList) {
			for (int i = 0; i < mListenerList.size(); i++) {
				final WeakReference<OnRequestFinishedListener> weakRef = mListenerList
						.get(i);
				final OnRequestFinishedListener listener = weakRef.get();
				if (listener != null) {
					listener.onRequestFinished(requestId, resultCode,
							resultData);
				} else {
					mListenerList.remove(i);
					i--;
				}
			}
		}
	}

	/**
	 * 发起请求.默认为显示等待框
	 * 
	 * @param type
	 * @param bundle
	 * @return
	 */
	public int request(int type, Bundle bundle) {
		return request(type, bundle, true);
	}

	/**
	 * request
	 * 
	 * @param type
	 * @param bundle
	 * @param isShow
	 *            是否显示等待框
	 * 
	 * @return the request Id
	 */
	public int request(int type, Bundle bundle, boolean isShow) {
		// 获取最后一个监听器,调用它的准备方法
		// if (mListenerList != null && mListenerList.size() > 0) {
		// mListenerList.get(mListenerList.size() - 1).get()
		// .onRequestPrepareListener();
		// }
		// fixed by ning.dai. WeakReference may be contain null.
		final int listLength = mListenerList.size();
		if (mListenerList != null && listLength > 0) {
			final OnRequestFinishedListener lst = mListenerList.get(
					listLength - 1).get();
			if (lst != null && isShow) {
				lst.onRequestPrepareListener();
			}
		}
		// Check if a match to this request is already launched
		final int requestSparseArrayLength = mRequestSparseArray.size();
		for (int i = 0; i < requestSparseArrayLength; i++) {
			final Intent savedIntent = mRequestSparseArray.valueAt(i);
			if (savedIntent
					.getIntExtra(PoCService.INTENT_EXTRA_WORKER_TYPE, -1) != type) {
				continue;
			}
			return mRequestSparseArray.keyAt(i);
		}
		final int requestId = sRandom.nextInt(MAX_RANDOM_REQUEST_ID);
		final Intent intent = new Intent(mContext, PoCService.class);
		intent.putExtra(PoCService.INTENT_EXTRA_WORKER_TYPE, type);
		intent.putExtra(PoCService.INTENT_EXTRA_RECEIVER, mEvalReceiver);
		intent.putExtra(PoCService.INTENT_EXTRA_REQUEST_ID, requestId);
		if (bundle != null) {
			intent.putExtras(bundle);
		}
		mContext.startService(intent);
		mRequestSparseArray.append(requestId, intent);
		return requestId;
	}

	/**
	 * 1.1获取验证码
	 * 
	 * @param phone
	 * @param type
	 * @param isShow
	 * @return
	 */
//	public int getCode(String phone, String type, boolean isShow) {
//		Bundle bundle = new Bundle();
//		bundle.putString(KeyBean.KEY_PHONE, phone);
//		bundle.putString(KeyBean.KEY_TYPE, type);
//		return request(PoCService.TYPE_INDEX_GETCODE, bundle, isShow);
//	}
}
